package andreafrancia.util.remote;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.AbstractList;
import java.util.List;
import javax.swing.event.EventListenerList;

/**
 * An Adapter to access to a {@link RemoteList} with a {@link java.util.List}
 * interface.
 * @param <T> the type of the element of the list.
 * @author Andrea Francia
 */
public class RemoteListAsList<T> extends AbstractList<T> implements Serializable 
{
    final private RemoteList<T> adaptee;
    private RemoteExceptionListenersSupport listenerSupport = 
            new RemoteExceptionListenersSupport();

    /**
     * Create a instance that act as a proxy for the specified 
     * {@link RemoteList}.
     * 
     * @param adaptee the proxy target, can not be {@code null}.
     * @throws IllegalArgumentException if {@code target} is {@code null}.
     */
    public RemoteListAsList(RemoteList<T> adaptee) {
        if(adaptee==null) {
            throw new IllegalArgumentException(
                    "Parameter 'adaptee' can not be null");
        }
        this.adaptee = adaptee;
    }

    /**
     * Retrieve the element at the specified index on the {@code target} list.
     * 
     * Invoke the {@code get(index)} on the {@code target}.
     * 
     * If the an {@link RemoteException} occours a 
     * {@link RemoteExceptionListener#exceptionThrown(java.rmi.RemoteException)} 
     * event is fired.
     * 
     * @param index the index 
     * @return the element at the specified position on the target list, or 
     *         {@code null} if a {@link RemoteException} occours.
     */
    @Override
    public T get(int index) {
        try {
            return adaptee.get(index);
        } catch (RemoteException ex) {
            listenerSupport.fireExceptionThrown(ex);
            return null;
        }
    }

    /**
     * Retrieve the size() of the target.
     * 
     * Invoke the {@code size()} on the {@code target}.
     * 
     * If the an {@link RemoteException} occours a 
     * {@link RemoteExceptionListener#exceptionThrown(java.rmi.RemoteException)} 
     * event is fired.
     * 
     * @return the size of the target list, or 
     *         {@code 0} (zero) if a {@link RemoteException} occours.
     */
    @Override
    public int size() {
        try {
            return adaptee.size();
        } catch (RemoteException ex) {
            listenerSupport.fireExceptionThrown(ex);
            return 0;
        }
    }

    /**
     * Add a {@link RemoteExceptionListener} to the RemotedList.
     * @param listener the listener to add.
     */
    public void addRemoteExceptionListener(RemoteExceptionListener listener) {
        listenerSupport.addRemoteExceptionListener(listener);
    }

    /**
     * Remove a {@link RemoteExceptionListener} from the RemotedList.
     * @param listener the listener to add.
     */
    public void removeRemoteExceptionListener(RemoteExceptionListener listener) 
    {
        listenerSupport.addRemoteExceptionListener(listener);
    }

    /**
     * Returns an array of all the <code>RemoteExceptionListener</code>s added
     * to this RemotedList with addRemoteExceptionListener().
     *
     * @return all of the <code>RemoteExceptionListener</code>s added or 
     *         an empty array if no listeners have been added
     */
    public RemoteExceptionListener[] getRemoteExceptionListeners() {
        return listenerSupport.getRemoteExceptionListeners();
    }
}
